package priv.xakml.demos.ftpserver;

import lombok.extern.slf4j.Slf4j;
import org.apache.ftpserver.DataConnectionConfigurationFactory;
import org.apache.ftpserver.FtpServer;
import org.apache.ftpserver.FtpServerFactory;
import org.apache.ftpserver.ftplet.Ftplet;
import org.apache.ftpserver.ftplet.UserManager;
import org.apache.ftpserver.impl.DefaultFtpServer;
import org.apache.ftpserver.listener.Listener;
import org.apache.ftpserver.listener.ListenerFactory;

import org.apache.ftpserver.usermanager.impl.PropertiesUserManager;
import org.apache.ftpserver.usermanager.impl.WritePermission;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ftpserver.usermanager.impl.BaseUser;

@Slf4j
@SpringBootApplication
public class FtpserverDemoApplication implements CommandLineRunner {

    private static final Logger logger = LoggerFactory.getLogger(FtpserverDemoApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(FtpserverDemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        printOssProfile(); //输出配置参数
        printFtpProfile();

        FtpServerFactory serverFactory = new FtpServerFactory();
        ListenerFactory listenerFactory = new ListenerFactory();

        //设置监听的端口
        listenerFactory.setPort(FtpServerSetting.getBindingPort());


        DataConnectionConfigurationFactory dataConnectionConfigurationFactory = new DataConnectionConfigurationFactory();
        //设置被动模式使用的段范围
        dataConnectionConfigurationFactory.setPassivePorts(FtpServerSetting.getPassivePorts());
        dataConnectionConfigurationFactory.setPassiveExternalAddress(FtpServerSetting.getPassiveExternalAddress());

        listenerFactory.setDataConnectionConfiguration(dataConnectionConfigurationFactory.createDataConnectionConfiguration());

        //3、增加SSL安全配置
//        SslConfigurationFactory ssl = new SslConfigurationFactory();
//        ssl.setKeystoreFile(new File("src/main/resources/ftpserver.jks"));
//        ssl.setKeystorePassword("password");
        //ssl.setSslProtocol("SSL");
        // set the SSL configuration for the listener
//        listenerFactory.setSslConfiguration(ssl.createSslConfiguration());
//        listenerFactory.setImplicitSsl(true);

        //4、替换默认的监听器
        Listener listener = listenerFactory.createListener();
        serverFactory.addListener("default", listener);
        //5、配置自定义用户事件
        Map<String, Ftplet> ftpLets = new HashMap();
        ftpLets.put("ftpService", new MyFtplet());
        serverFactory.setFtplets(ftpLets);
        //6、读取用户的配置信息
        //注意：配置文件位于resources目录下，如果项目使用内置容器打成jar包发布，FTPServer无法直接直接读取Jar包中的配置文件。
        //解决办法：将文件复制到指定目录(本文指定到根目录)下然后FTPServer才能读取到。
//        PropertiesUserManagerFactory userManagerFactory = new PropertiesUserManagerFactory();
//        String tempPath = System.getProperty("java.io.tmpdir") + System.currentTimeMillis() + ".properties";
//        File tempConfig = new File(tempPath);
//        ClassPathResource resource = new ClassPathResource("users.properties");
//        IOUtils.copy(resource.getInputStream(), new FileOutputStream(tempConfig));
//        userManagerFactory.setFile(tempConfig);
//        userManagerFactory.setPasswordEncryptor(new ClearTextPasswordEncryptor());  //密码以明文的方式
//        serverFactory.setUserManager(userManagerFactory.createUserManager());

        //6.2、基于数据库来存储用户实例
//        DbUserManagerFactory dbUserManagerFactory = new DbUserManagerFactory();
//        //todo....
//        dbUserManagerFactory.setDataSource(dataSource);
//        dbUserManagerFactory.setAdminName("admin");
//        dbUserManagerFactory.setSqlUserAdmin("SELECT userid FROM FTP_USER WHERE userid='{userid}' AND userid='admin'");
//        dbUserManagerFactory.setSqlUserInsert("INSERT INTO FTP_USER (userid, userpassword, homedirectory, " +
//                "enableflag, writepermission, idletime, uploadrate, downloadrate) VALUES " +
//                "('{userid}', '{userpassword}', '{homedirectory}', {enableflag}, " +
//                "{writepermission}, {idletime}, uploadrate}, {downloadrate})");
//        dbUserManagerFactory.setSqlUserDelete("DELETE FROM FTP_USER WHERE userid = '{userid}'");
//        dbUserManagerFactory.setSqlUserUpdate("UPDATE FTP_USER SET userpassword='{userpassword}',homedirectory='{homedirectory}',enableflag={enableflag},writepermission={writepermission},idletime={idletime},uploadrate={uploadrate},downloadrate={downloadrate},maxloginnumber={maxloginnumber}, maxloginperip={maxloginperip} WHERE userid='{userid}'");
//        dbUserManagerFactory.setSqlUserSelect("SELECT * FROM FTP_USER WHERE userid = '{userid}'");
//        dbUserManagerFactory.setSqlUserSelectAll("SELECT userid FROM FTP_USER ORDER BY userid");
//        dbUserManagerFactory.setSqlUserAuthenticate("SELECT userid, userpassword FROM FTP_USER WHERE userid='{userid}'");
//        dbUserManagerFactory.setPasswordEncryptor(new ClearTextPasswordEncryptor());
//        serverFactory.setUserManager(dbUserManagerFactory.createUserManager());
        BaseUser user = new BaseUser();
        user.setName("user_weixin_pic_upload");
        user.setPassword("5gD7RYJX");
        logger.info("默认根目录：{}", FtpServerSetting.getHomeDirectory());
        //默认用户的根目录
        user.setHomeDirectory(FtpServerSetting.getHomeDirectory());
        user.setEnabled(true);

        List authorities = new ArrayList();
        authorities.add(new WritePermission());
        user.setAuthorities(authorities);

        // 实例化 ftp server & start the server
        FtpServer server = serverFactory.createServer();

        UserManager um = ((DefaultFtpServer) server).getUserManager();
        um.save(user);
        if (um instanceof PropertiesUserManager) {
            File file = ((PropertiesUserManager) um).getFile();

            if (file != null) {
                System.out.println("User saved to file: " + file.getAbsolutePath());
            } else {
                System.err.println("User manager does not have a file configured, will not save user to file");
            }
        } else {
            System.out.println("User saved");
        }

        server.start();
        System.out.println("started.");
    }

    private void printOssProfile(){
        logger.info("二级路径: {}", NetworkStorageSetting.getOssPkgPicDic());
        logger.info("节点名称: {}", NetworkStorageSetting.getOssMainBucketName());
        logger.info("ossEndPoint: {}", NetworkStorageSetting.getOssEndPoint());
        logger.info("ossAccessKeyId: {}", NetworkStorageSetting.getOssAccessKeyId());
        logger.info("ossAccessSecretKey: {}", NetworkStorageSetting.getOssAccessKeySecret());
        logger.info("ossServerIp: {}", NetworkStorageSetting.getOssServerIp());
    }

    private void printFtpProfile(){
        logger.info("监听端口: {}", FtpServerSetting.getBindingPort());
        logger.info("被动模式使用端口: {}", FtpServerSetting.getPassivePorts());
        logger.info("被动模式使用地址: {}", FtpServerSetting.getPassiveExternalAddress());
        logger.info("用户主目录: {}", FtpServerSetting.getHomeDirectory());
    }
}

/**
 * 参考链接
 * http://mina.apache.org/ftpserver-project/embedding_ftpserver.html
 * https://blog.csdn.net/m0_37595954/article/details/103975507
 */


/***
 * spring boot 命令行参数
 * https://docs.spring.io/spring-boot/docs/1.4.1.RELEASE/reference/html/boot-features-external-config.html
 * https://blog.csdn.net/weixin_35973945/article/details/81118191?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-2.control&dist_request_id=1331302.9262.16182924182251881&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-2.control
 * https://blog.csdn.net/poem_2010/article/details/84786894
 *
 * java -jar ftpserver-demo-0.0.1-SNAPSHOT.jar --spring-config-location=""
 **/